import abc
import json
import time
from tkinter import messagebox

import requests

from config import env, Env
from le_engine.attack import attack
from le_engine.base import LittleEmpire
from le_engine.config import IconName, CommonConfig
from le_engine.dig_mojo import TaskDigMojo
from le_engine.train import Train
from ui_engine.task_manager import task_manager

from utils.logger import log
from utils.utils import account_config, CommonUtils


class CommonTask(abc.ABC):
    TASK_NAME = "COMMON"

    def __init__(self, ip, port, username, psw, sim_index=None):
        self.ip = ip
        self.port = port
        self.username = username
        self.psw = psw

        self.sim_index = sim_index
        self.auto_get_ip_port()
        self.name = f"{ip}:{port}-{username}-{sim_index}-{self.TASK_NAME}"

    def auto_get_ip_port(self):
        # 自动分配设备
        pass

    def send_task(self):
        args = self.get_args()
        kwargs = self.get_kwargs()

        if env == Env.prod:
            if self.username not in json.loads(requests.get("http://124.71.106.203/list").text)["list"]:
                return False, "小家伙，你哪里偷来的口令！老实交代。"

        ok, msg = task_manager.start_task(self.name, self._task, *args, **kwargs)
        return ok, msg

    def stop_task(self):
        task_manager.stop_task(self.name)

    @abc.abstractmethod
    def _task(self, *args, **kwargs):
        time.sleep(1)

    def get_args(self) -> tuple:
        return self.ip, self.port

    def get_kwargs(self) -> dict:
        return {"username": self.username, "psw": self.psw}


class AttackTask(CommonTask):
    TASK_NAME = "刷功勋"

    def _task(self, stop_event, ip, port, username, psw):
        le = LittleEmpire(ip, port, username=username, psw=psw)
        attack(le, forever=True, event=stop_event)


class TrainTask(CommonTask):
    TASK_NAME = "刷训练场"

    def _task(self, stop_event, ip, port, username, psw):
        le = LittleEmpire(ip, port, username=username, psw=psw)
        t = Train(le, event=stop_event)
        t.start()


class DigMojo(CommonTask):
    TASK_NAME = "挖矿"

    def _task(self, stop_event, ip, port, username, psw):
        le = LittleEmpire(ip, port, username=username, psw=psw)
        TaskDigMojo(le, stop_event, sim_index=self.sim_index).start()


class BrushMerit(CommonTask):
    TASK_NAME = "小号刷功勋"

    def wait_attack(self, le, stop_event):

        time_info = [i.get_text() for i in le.client(textContains="你的部队")]
        if time_info:
            max_seconds = max([CommonUtils.extract_seconds(item) for item in time_info])
            log.info(f"所有牢笼都在进攻，需要等待:{max_seconds}秒", extra={"pk": le.pk})
            for remaining in range(max_seconds, 0, -1):
                if stop_event and stop_event.is_set():
                    log.info("已停止刷功勋", extra={"pk": le.pk})
                    return False, None
                minutes = remaining // 60
                seconds = remaining % 60
                print(f"\r还剩 {minutes} 分 {seconds} 秒", end="", flush=True)
                time.sleep(1)
        log.info("等待结束", extra={"pk": le.pk})
        le.client.click(*CommonConfig.close_position)
        time.sleep(5)
        return True, None

    def _task(self, stop_event, ip, port, username, psw):
        le = LittleEmpire(ip, port, username=username, psw=psw)

        while True:
            if stop_event and stop_event.is_set():
                log.info(f"{le.username} 已停止小号刷功勋", extra={"pk": le.pk})
                return False, "已停止小号刷功勋"
            if not le.inter_game():
                continue

            cage_position = CommonConfig.cage_config.get("common", {}).get("cage_position")[0]

            target = account_config().get("brush_merit_map")[self.username]

            le.client.click(*cage_position)
            le.im.click_image(CommonConfig.img_path(IconName.cage_check), max_retries=3)
            if stop_event and stop_event.is_set():
                log.info(f"{le.username} 已停止小号刷功勋", extra={"pk": le.pk})
                return False, "已停止小号刷功勋"

            if le.client(text="你的仇家").wait(timeout=CommonConfig.n_t_o) and le.client(text=target).wait(timeout=CommonConfig.n_t_o):
                le.client(text=target).click_exists(timeout=CommonConfig.n_t_o)
                if le.im.click_image(CommonConfig.img_path(IconName.ll_attack), max_retries=3):
                    if le.im.click_image(CommonConfig.img_path(IconName.read), max_retries=3):

                        if stop_event and stop_event.is_set():
                            log.info(f"{le.username} 已停止小号刷功勋", extra={"pk": le.pk})
                            return False, "已停止小号刷功勋"

                        if le.client(text="功勋").click_exists(timeout=CommonConfig.n_t_o):
                            if le.im.click_image(CommonConfig.img_path(IconName.confirm), max_retries=3):
                                if le.client(text="你的仇家").wait(timeout=CommonConfig.n_t_o):
                                    log.info(f"发起对 {target} 进攻，成功", extra={"pk": le.pk})

                                    le.im.click_image(CommonConfig.img_path(IconName.close), max_retries=3)
            elif le.client(textContains="信件").wait(timeout=CommonConfig.n_t_o):
                # le.im.click_image(CommonConfig.img_path(IconName.jingongzhanbao), max_retries=3)
                le.client.click(0.284, 0.149)
                self.wait_attack(le, stop_event)
                continue
            else:
                log.info(f"发起对 {target} 进攻, 失败", extra={"pk": le.pk})
                continue

            # 如果所有牢笼都在进攻，识别行军最大时间，进行等待
            le.client.click(*CommonConfig.center_position)
            time.sleep(1)
            le.client.click(*CommonConfig.cage_check)
            if le.client(textContains="信件").wait(timeout=CommonConfig.n_t_o):
                # le.im.click_image(CommonConfig.img_path(IconName.jingongzhanbao), max_retries=3)
                le.client.click(0.284, 0.149)
            le.client(textContains="你的部队").wait(timeout=CommonConfig.n_t_o)
            self.wait_attack(le, stop_event)


class StepTest(CommonTask):
    TASK_NAME = "测试"

    def _task(self, stop_event, ip, port, username, psw):
        log.info("测试用")